package com.wocai.jrt.orgadmin.stats.service.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;

import com.alibaba.fastjson.JSON;
import com.vteba.cache.annotation.Prefix;
import com.vteba.utils.date.DateUtils;
import com.wocai.jrt.admin.common.cache.Const;
import com.wocai.jrt.orgadmin.orders.model.Orders;
import com.wocai.jrt.orgadmin.orders.model.OrdersBean;
import com.wocai.jrt.orgadmin.orders.service.spi.OrdersService;
import com.wocai.jrt.orgadmin.product.model.Product;
import com.wocai.jrt.orgadmin.product.model.ProductBean;
import com.wocai.jrt.orgadmin.product.service.spi.ProductService;
import com.wocai.jrt.orgadmin.stats.bean.OrgProductEmpStatsResBean;
import com.wocai.jrt.orgadmin.stats.bean.ProductEmpStatsReqBean;
import com.wocai.jrt.orgadmin.stats.bean.ProductEmpStatsResBean;
import com.wocai.jrt.orgadmin.stats.bean.ProductRecruitProgressEleBean;
import com.wocai.jrt.orgadmin.stats.bean.ProductRecruitProgressResBean;
import com.wocai.jrt.orgadmin.stats.bean.ProductStatResBean;
import com.wocai.jrt.orgadmin.stats.service.spi.ProductStatsService;

@Named
public class ProductStatsServiceImpl implements ProductStatsService {
	private static final Logger LOGGER = LoggerFactory.getLogger(ProductStatsServiceImpl.class);
	@Inject
	private ProductService productServiceImpl;

	@Inject
	private OrdersService orderServiceImpl;
	
	class RecruitException extends Exception{

		public RecruitException(String s)
	    {
	        super(s);
	    }
		    
		private static final long serialVersionUID = 3398776087787991014L;
		
	}

	@Override
	@Prefix(Const.PREFIX_PRODUCT_RATE)
	@CachePut(value = Const.STATS, keyGenerator = "redisKeyGenerator")
	public List<ProductStatResBean> putProductStatsResBeanListToRedis(String orgId) {
		List<ProductStatResBean> productStatsList = new ArrayList<ProductStatResBean>();
		productStatsList = this.fetchProductStatsResBeanList(orgId);
		return productStatsList;
	}

	@Override
	@Prefix(Const.PREFIX_PRODUCT_PROGRESS)
	@CachePut(value = Const.STATS, keyGenerator = "redisKeyGenerator")
	public ProductRecruitProgressResBean putUncompletedProductRecruitProgressToRedis(String orgId) {
		ProductRecruitProgressResBean prp = new ProductRecruitProgressResBean();
		prp = this.fetchUncompletedProductRecruitProgress(orgId);
		return prp;
	}
	
	@Override
	@Prefix(Const.PREFIX_PRODUCT_EMP)
	@CachePut(value = Const.STATS, keyGenerator = "redisKeyGenerator")
	public OrgProductEmpStatsResBean putOrgProductEmpStatsResBeanToRedis(ProductEmpStatsReqBean productEmpStatsReqBean) {
		OrgProductEmpStatsResBean bean = new OrgProductEmpStatsResBean();
		bean = this.fetchOrgProductEmpStatsResBean(productEmpStatsReqBean);
		return bean;
	}

	@Override
	@Prefix(Const.PREFIX_PRODUCT_RATE)
	@Cacheable(value = Const.STATS, keyGenerator = "redisKeyGenerator")
	public List<ProductStatResBean> getProductStatsResBeanList(String orgId) {
		List<ProductStatResBean> productStatsList = new ArrayList<ProductStatResBean>();
		productStatsList = this.fetchProductStatsResBeanList(orgId);
		return productStatsList;
	}

	@Override
	@Prefix(Const.PREFIX_PRODUCT_PROGRESS)
	@Cacheable(value = Const.STATS, keyGenerator = "redisKeyGenerator")
	public ProductRecruitProgressResBean getUncompletedProductRecruitProgressList(String orgId) {
		ProductRecruitProgressResBean prp = new ProductRecruitProgressResBean();
		prp = this.fetchUncompletedProductRecruitProgress(orgId);
		return prp;
	}

	@Override
	@Prefix(Const.PREFIX_PRODUCT_EMP)
	@Cacheable(value = Const.STATS, keyGenerator = "redisKeyGenerator")
	public OrgProductEmpStatsResBean getOrgProductEmpStatsResBean(ProductEmpStatsReqBean productEmpStatsReqBean) {
		OrgProductEmpStatsResBean bean = new OrgProductEmpStatsResBean();
		bean = this.fetchOrgProductEmpStatsResBean(productEmpStatsReqBean);
		return bean;
	}

	/**
	 * 获取某个机构下产品募集速率数据
	 * 
	 * @param productStatsReqBean
	 * @param orgId
	 * @return List ProductStatResBean
	 */
	public List<ProductStatResBean> fetchProductStatsResBeanList(String orgId) {
		List<ProductStatResBean> productStatsList = new ArrayList<ProductStatResBean>();
		ProductBean product = new ProductBean();
		product.createCriteria().andOrgIdEqualTo(orgId).andStateNotEqualTo(0).andAuditStateEqualTo(1);
		// product.setStart(0);
		// product.setPageSize(5);
		product.setOrderBy("create_time desc");
		OrdersBean order = new OrdersBean();
		List<Integer> stateList = new ArrayList<Integer>();
		stateList.add(6);
		stateList.add(7);
		stateList.add(8);
		stateList.add(3);
		order.createCriteria().andOrgIdEqualTo(orgId).andStateIn(stateList);
		order.setOrderBy("pay_time asc");
		
		// order.setState(6);
		if (LOGGER.isInfoEnabled()) {
			LOGGER.info("query product list params: [{}]", JSON.toJSONString(product));
			LOGGER.info("query orders list params: [{}]", JSON.toJSONString(order));
		}
		List<Product> productList = productServiceImpl.queryForList(product);
		List<Orders> ordersList = orderServiceImpl.queryForList(order);
		for (Product p : productList) {
			if (LOGGER.isInfoEnabled()) {
				LOGGER.info("product brief name: [{}]", p.getBriefName());
			}
			ProductStatResBean productStatResBean = new ProductStatResBean();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			// 初始化该产品订单列表
			List<Orders> productOrdersList = new ArrayList<Orders>();
			// 获取该产品所有订单 TODO 从数据库获取
			for (Orders o : ordersList) {
				if (o.getProductId().equals(p.getId())) {
					productOrdersList.add(o);
				}
			}
			// 计算出已经销售的天数 --至产品募集完成 --至今
			long salesTerm = 0;
			if (p.getState() == 2) { // 募集完成的产品
				try {
					if (productOrdersList.size() == 0) { // 该产品订单列表为空，天数为募集开始至募集结束
						salesTerm = (sdf.parse(sdf.format(p.getRecruitEndTime())).getTime() - sdf
								.parse(sdf.format(p.getRecruitStartTime())).getTime())
								/ (1000 * 3600 * 24);
					} else { // 该产品订单列表不为空，天数为募集开始至该购买产品最近成交的订单的日期
						Date max = productOrdersList.get(productOrdersList.size() - 1).getPayTime();
						salesTerm = (sdf.parse(sdf.format(max)).getTime() - sdf.parse(
								sdf.format(p.getRecruitStartTime())).getTime())
								/ (1000 * 3600 * 24);
					}
				} catch (ParseException e) {
					LOGGER.error("calculate salesTerm error .msg=[{}]", e.getMessage());
				}
				;
			} else if (p.getState() == 1) { // 正在募集
				try {
					if (productOrdersList.size() == 0) { // 该产品订单列表为空，天数为募集开始至当天
															// TODO
															// 产品募集结束状态改变是不是自动的？
						salesTerm = (sdf.parse(sdf.format(DateUtils.getNow())).getTime() - sdf
								.parse(sdf.format(p.getRecruitStartTime())).getTime())
								/ (1000 * 3600 * 24);
					} else { // 该产品订单列表不为空，天数为募集开始至该购买产品最近成交的订单的日期
						Date max = productOrdersList.get(productOrdersList.size() - 1).getPayTime();
						salesTerm = (sdf.parse(sdf.format(max)).getTime() - sdf.parse(
								sdf.format(p.getRecruitStartTime())).getTime())
								/ (1000 * 3600 * 24);
					}
				} catch (ParseException e) {
					LOGGER.error("calculate salesTerm error .msg=[{}]", e.getMessage());
				}
			}
			// 初始化临时数组 用于保存产品销售时每天的募集程度 百分制
			// 初始化临时数组 用于保存产品销售每天的已募集金额
			if (salesTerm < 0) {
				salesTerm = 0;
			}
			Double[] percent = new Double[(int) salesTerm + 1];
			Double[] amount = new Double[(int) salesTerm + 1];
			Arrays.fill(percent, 0.0);
			Arrays.fill(amount, 0.0);
			// 初始化上一个有成交的募集天数
			long lastNum = 0;
			// 基金规模
			Double productScale = p.getScale();
			// 遍历该产品订单列表 订单列表按照时间升序
			for (Orders o : productOrdersList) {
				long dayNum = 0;
				try {
 					dayNum = (sdf.parse(sdf.format(o.getPayTime())).getTime() - sdf.parse(
							sdf.format(p.getRecruitStartTime())).getTime())
							/ (1000 * 3600 * 24);
				} catch (ParseException e) {
					LOGGER.error("calculate order dayNum parse error .msg=[{}]", e.getMessage());
				} catch(NullPointerException e){
					LOGGER.error("NullPointExcetion error .msg=[{}]", e.getMessage());
					continue;
				}
				if (lastNum == dayNum) { // 如果此订单与上一个订单的日期相同
					percent[(int) dayNum] += (o.getOrderAmount() / productScale) * 100;
					amount[(int) dayNum] += o.getOrderAmount();
				} else if (dayNum - lastNum > 1) { // 某些没有成交订单的日期
					for (int i = 1; i < dayNum - lastNum; i++) {
						percent[(int) lastNum + i] = percent[(int) lastNum];
						amount[(int) lastNum + i] = amount[(int) lastNum];
					}
					percent[(int) dayNum] = percent[(int) lastNum]
							+ (o.getOrderAmount() / productScale) * 100;
					amount[(int) dayNum] = amount[(int) lastNum]
							+ o.getOrderAmount();
					// 修改上一个募集天数
					lastNum = dayNum;
				} else {
					// 加上上一个日期的募集进度。再加次订单的进度
					if (dayNum < 0) {
						LOGGER.error("calculate order dayNum error .msg=[{}]", dayNum);
						try {
							throw new RecruitException("募集天数为负,订单支付时间先于产品募集开始时间");
						} catch (RecruitException e) {
							LOGGER.error("募集天数为负 .");
							continue;
						}
					}
					percent[(int) dayNum] = percent[(int) lastNum]
							+ (o.getOrderAmount() / productScale) * 100;
					amount[(int) dayNum] = amount[(int) lastNum]
							+ o.getOrderAmount();
					// 修改上一个募集天数
					lastNum = dayNum;
				}
			}
			// 封装数据
			productStatResBean.setSalePercent(percent);
			productStatResBean.setAmount(amount);
			productStatResBean.setName(p.getBriefName());
			productStatResBean.setProductId(p.getId());
			productStatResBean.setSalesTerm(salesTerm);
			productStatResBean.setProductScale(productScale);

			productStatsList.add(productStatResBean);
		}
		return productStatsList;
	}

	/**
	 * 获取单个机构当前售卖产品募集进度
	 * 
	 * @param orgId
	 * @return
	 */
	public ProductRecruitProgressResBean fetchUncompletedProductRecruitProgress(String orgId) {
		ProductRecruitProgressResBean prp = new ProductRecruitProgressResBean();
//		List<Double> recruitRatelist = new ArrayList<Double>();
//		List<Double> scaleList = new ArrayList<Double>();
		List<String> productNameList = new ArrayList<String>();
		// 查询该机构正在上线的产品
		if (LOGGER.isInfoEnabled()) {
			LOGGER.info("query uncompleted product recruit progress list params: [{}]", JSON.toJSONString(orgId));
		}
		ProductEmpStatsReqBean productEmpStatsReqBean = new ProductEmpStatsReqBean();
		productEmpStatsReqBean.setOrgId(orgId);
		List<ProductRecruitProgressEleBean> productRecruitProgressEleBeanList = orderServiceImpl.getUncompletedProductRecruitProgress(productEmpStatsReqBean);
		// 循环遍历
		try {
			for (ProductRecruitProgressEleBean p : productRecruitProgressEleBeanList) {
//				scaleList.add(p.getScale());
				productNameList.add(p.getBriefName());
				if(p.getRecruitProgress() == null){
					p.setRecruitProgress(0.0);
				}
//				}else{
//					recruitRatelist.add(p.getRecruitProgress());
//				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			LOGGER.error("Loop add product recreut progress error .msg=[{}]", e.getMessage());
			return null;
		}
		// 封装数据
		prp.setOrgId(orgId);
		prp.setProductNameList(productNameList);
		prp.setProductRecruitProgressEleBeanList(productRecruitProgressEleBeanList);
//		prp.setScaleList(scaleList);
//		prp.setRecruitRatelist(recruitRatelist);
		return prp;
	}
	
	/**
	 * 获取单个机构的产品团队销售数据
	 * @param productEmpStatsReqBean
	 * @return
	 */
	public OrgProductEmpStatsResBean fetchOrgProductEmpStatsResBean(ProductEmpStatsReqBean productEmpStatsReqBean) {
		OrgProductEmpStatsResBean bean = new OrgProductEmpStatsResBean();
		List<ProductEmpStatsResBean> eBean = orderServiceImpl
				.getProductEmpStats(productEmpStatsReqBean);
		bean.setProductEmpStatsResBeanList(eBean);
		return bean;
	}
	
}
